/*
 * Copyright 2020 lcnap
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package pers.lcnap.simplerpc.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 简单的 bean 容器。存储 代理类/服务类实现。
 */
public class BeanContext {

    private final static ConcurrentHashMap<Class<?>, Object> serviceImpls = new ConcurrentHashMap<>();
    private final static ConcurrentHashMap<Class<?>, Object> proxy = new ConcurrentHashMap<>();

    /**
     * 根据接口，返回 实现类。
     *
     * @param clazz 接口类
     * @param <T>
     * @return
     */
    public static <T> T getServiceImpl(Class<T> clazz) {
        return (T) serviceImpls.get(clazz);
    }

    /**
     * @param clazz
     * @param <T>
     * @return
     * @throws Exception
     * @see BeanContext#getServiceImpl(String)
     */
    public static <T> T getServiceImpl(String clazz) throws Exception {
        return (T) serviceImpls.get(Class.forName(clazz));
    }

    /**
     * <code>serviceImpl</code> 实例化，并以其第一个接口为键值存储在 Map 中.
     *
     * @param serviceImpl 服务实现类
     * @throws Exception
     */
    public static void putServiceImpl(Class<?> serviceImpl) throws Exception {
        Class<?>[] interfaces = serviceImpl.getInterfaces();
        assert interfaces.length > 0;
        serviceImpls.put(interfaces[0], newBean(serviceImpl));
    }

    /**
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getRpcProxy(Class<T> clazz) {
        return (T) proxy.get(clazz);
    }

    public static void putRpcProxy(Class<?> proxyInterface, InvocationHandler handler) throws Exception {
        proxy.put(proxyInterface, newRpcProxy(proxyInterface, handler));
    }

    /**
     * 根据给定接口，生成代理类。
     *
     * @param clazz   接口
     * @param handler 代理逻辑类
     * @return
     */
    public static Object newRpcProxy(Class<?> clazz, InvocationHandler handler) {
        return Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, handler);
    }

    /**
     * 实例化服务实现类。不支持内部类。
     *
     * @param clazz 服务实现类
     * @return 服务实现类实例
     * @throws Exception
     */
    public static Object newBean(Class<?> clazz) throws Exception {
        Constructor<?> constructor = clazz.getConstructors()[0];
        Object instance = constructor.newInstance();
        return instance;
    }

}
